<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
<script>
  const html = `
  <div class="container">
    <header class="header" id="header">
      <nav>
        <li><a href="http://ssss.com">menu home home home</a></li>
        <li><a href="http://ssss.com">  menu user</a></li>
      </nav>
    </header>
    <main>
      <  section  >
        <ul>
          <li>select 1</li>
          <li>  select 2</li>
          <li>select 3  </li>
          <li>  select 3  </li>
        </ul>
      </section>
      <article>
        <img src="https://image.jpg" /  >
        <div>
          some text
        </div>
      </article>
    <  /  main>
    <footer>
      footer
    </footer>
  </div>
  `

  function findTag (str) {
    if (str.trim().length) {
      return str.trim().match(/[a-zA-Z]+/)[0]
    }
  }

  const tags = []
  const parents = []

  html.replace(/<[^>]+>|((?<=[^<]).+?(?=<))/gms, (substring) => {
    const tag = findTag(substring)
    if (!tag) return;
    const tagId = `${tag}-${Math.abs(Math.random() * Math.pow(10, 10))}`

    substring = substring.replace(/<\s*/, '<')
    substring = substring.replace(/\s*>/, '>')

    if (substring.startsWith('</')) {
      substring = substring.replace(/<\/\s*/, '<\/')
    }

    if (substring.startsWith('</')) {
      parents.pop()
      return substring
    }

    const node = {
      tag, tagId, node: substring, children: []
    }

    const __parents = [...parents]
    const parentNode = __parents.pop()
    // .join('-')

    node.parent = __parents.reduce(
      (prev, next) => {
        return (prev ? `${prev}-${next.tag}` : next.tag)
      }, ''
    )

    node.parent += parentNode ? (node.parent ? '-' + (parentNode.tagId) : parentNode.tagId) : ''
    node.parentNode = parentNode

    if (substring.startsWith('<')) {
      node.type = 'element'

      if (substring.endsWith('/>') || substring.startsWith('<img')) {
      } else {
        parents.push(node)
      }
    } else {
      node.type = 'text'
    }

    tags.push(node)

    return substring
  })

  // 解析后的数组
  console.log(tags)

  let tree = {}

  for (let item of tags) {
    if (item.parent) {
      const parentIndex = item.parent.lastIndexOf('-')
      const parentKey = item.parent.substring(0, parentIndex)
      tree[`${parentKey}-${item.tagId}`] = item
    } else {
      tree[item.tagId] = item
    }
  }

  while (Object.keys(tree).length > 1) {
    const items = Object.entries(tree).sort(([keyA], [keyB]) => (keyA.length - keyB.length))
    const [selfKey, item] = items.pop()

    tree[item.parent].children.push(item)

    delete tree[selfKey]
  }

  // 解析后的数组 重新构造为 【树形结构】
  console.log(tree)
</script>
</body>
</html>
